package com.swak.consistency.core.proxy;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

import com.swak.annotation.Tcc;
import com.swak.asm.MethodCache;
import com.swak.asm.MethodCache.ClassMeta;
import com.swak.asm.Wrapper;
import com.swak.consistency.core.aspect.ConsistencyProceeding;

/**
 * AbstractConsistencyProxy.
 * 
 * 特定模式下才能使用；
 * 
 * @author 618lf
 */
@SuppressWarnings("unchecked")
public abstract class AbstractConsistencyProxy<T> implements ConsistencyProxy<T> {

	/**
	 * 申明的类型
	 */
	private Class<?> declareClass;
	private Field declareField;

	/**
	 * 实际的 Service
	 */
	private Class<T> type;
	private T actualService;
	private Wrapper wrapper;
	private ClassMeta classMeta;

	public AbstractConsistencyProxy(Field field, T service) {
		this.declareClass = field.getDeclaringClass();
		this.declareField = field;
		this.type = (Class<T>) field.getType();
		this.actualService = service;
		this.classMeta = MethodCache.get(type);
		this.wrapper = Wrapper.getWrapper(type);
	}

	protected Object invoke(Method method, Object[] args) throws Throwable {
		if (method.isAnnotationPresent(Tcc.class)) {
			return ConsistencyProceeding.of().setDeclareClass(declareClass).setDeclareField(declareField)
					.setTarget(type).setMethod(method).setArgs(args).setProceeding(() -> {
						return this.doConsistencyInvoke(method, args);
					}).transmit();
		}
		return this.doConsistencyInvoke(method, args);
	}

	private Object doConsistencyInvoke(Method method, Object[] args) throws Exception {
		String mn = classMeta.lookup(method).getMethodDesc();
		return wrapper.invokeMethod(actualService, mn, args);
	}
}